#include "main.h"
/*
 * SHUNT_CAL is a conversion constant that represents the shunt resistance
 * used to calculate current value in Amps. This also sets the resolution
 * (CURRENT_LSB) for the current register.
 *
 * SHUNT_CAL is 15 bits wide (0 - 32768)
 *
 * SHUNT_CAL = 13107.2 x 10^6 x CURRENT_LSB x Rshunt
 *
 * CURRENT_LSB = Max Expected Current / 2^19
 */
float CURRENT_LSB;

//ina228初始化配置
int ina228_init(uint8_t i2c_master_port)
{
	mvar.msr.mAh_tmp=mvar.count.Count_mAh;				//读取历史记录mAh
	mvar.msr.mWh_tmp=mvar.count.Count_mWh;				//读取历史记录mWh
	mvar.msr.max_mA=mvar.count.Count_Max_mA;			//读取历史记录Max_mAh
	mvar.msr.max_mW=mvar.count.Count_Max_mW;			//读取历史记录Max_mWh

	i2c_init(i2c_master_port,1,0);
	i2c_write_short(i2c_master_port, INA228_SLAVE_ADDRESS, INA228_CONFIG, 0x8000);					// INA228复位

	printf("Manufacturer ID:    0x%04X\n",i2c_read_short(i2c_master_port, INA228_SLAVE_ADDRESS, INA228_MANUFACTURER_ID));
	printf("Device ID:          0x%04X\n",i2c_read_short(i2c_master_port, INA228_SLAVE_ADDRESS, INA228_DEVICE_ID));
	if (i2c_read_short(i2c_master_port, INA228_SLAVE_ADDRESS, INA228_DEVICE_ID) != INA228_ID_NUM) 
    {
        Printf("Not find ina228\n");
        return -1;
    }
	ina228_set_config(i2c_master_port);				//INA228芯片配置
    ina228_set_adc_config(i2c_master_port);			//INA228片上ADC配置
	ina228_set_shunt_cal(i2c_master_port);			//设置校准值
	return 0;
}

//INA228芯片配置
void ina228_set_config(uint8_t i2c_master_port)
{
    uint16_t data = mvar.store.Config_RST<<15|mvar.store.Config_RSTACC<<14|mvar.store.Config_CONVDLY<<6|mvar.store.Config_TEMPCOMP<<5|mvar.store.Config_ADCRANGE<<4;
    i2c_write_short(i2c_master_port, INA228_SLAVE_ADDRESS, INA228_CONFIG, data);
    printf("INA228_Config_Reg:	%x\n",data);
}

//ina228片上ADC配置
void ina228_set_adc_config(uint8_t i2c_master_port)
{
    uint16_t data = mvar.store.ADC_ADCMode<<12|mvar.store.ADC_VBUSCT<<9|mvar.store.ADC_VSHCT<<6|mvar.store.ADC_VTCT<<3|mvar.store.ADC_ADCAVG;
    i2c_write_short(i2c_master_port, INA228_SLAVE_ADDRESS, INA228_ADC_CONFIG, data);
    printf("ADC_Config_Reg:		%x\n",data);
}

//分流电阻校准，单位：毫欧,ppm/℃
void ina228_set_shunt_cal(uint8_t i2c_master_port)
{
	uint16_t SHUNT_CAL;
    
    CURRENT_LSB = mvar.store.MAXcurrent/524288.0;

	if(mvar.store.Config_ADCRANGE == 1)
		SHUNT_CAL = 131072  * CURRENT_LSB / 1000 * 100000 * (mvar.store.res/1000000.0) * 4;
	else
        SHUNT_CAL = 131072  * CURRENT_LSB / 1000 * 100000 * (mvar.store.res/1000000.0);

	i2c_write_short(i2c_master_port, INA228_SLAVE_ADDRESS, INA228_SHUNT_CAL, SHUNT_CAL);    //设置shunt_cal
    i2c_write_short(i2c_master_port, INA228_SLAVE_ADDRESS, INA228_SHUNT_TEMPCO, mvar.store.Config_TEMPCOMP_PPM);       //设置温度补偿系数
    printf("ADCRange=%d      CURRENT_LSB=%f      SHUNT_CAL = %d      PPM = %d\n",mvar.store.Config_ADCRANGE,CURRENT_LSB,SHUNT_CAL,mvar.store.Config_TEMPCOMP_PPM);
}

//将累积寄存器 ENERGY 和 CHARGE 的内容复位为 0
void ina228_reset_acc(uint8_t i2c_master_port){
	uint16_t data = mvar.store.Config_RST<<15|mvar.store.Config_RSTACC<<14|mvar.store.Config_CONVDLY<<6|mvar.store.Config_TEMPCOMP<<5|mvar.store.Config_ADCRANGE<<4;
	data |= 0x4000;
    i2c_write_short(i2c_master_port, INA228_SLAVE_ADDRESS, INA228_CONFIG, data);
}

float ina228_voltage(uint8_t i2c_master_port)														//获取电压，单位mV
{
	int32_t iBusVoltage;
	float fBusVoltage;
	bool sign;

	i2c_read_buf(i2c_master_port, INA228_SLAVE_ADDRESS, INA228_VBUS, (uint8_t *)&iBusVoltage, 3);
	sign = iBusVoltage & 0x80;
	iBusVoltage = __bswap32(iBusVoltage & 0xFFFFFF) >> 12;
	if (sign) iBusVoltage += 0xFFF00000;
	fBusVoltage = (iBusVoltage) * 0.1953125;                                                     //电压转换因子195.3125µV/LSB该处放大了1000倍输出单位为mV

	return (fBusVoltage);
}

float ina228_current(uint8_t i2c_master_port)														//获取电流，单位mA？
{
	int32_t iCurrent;
	float fCurrent;
	bool sign;

	i2c_read_buf(i2c_master_port, INA228_SLAVE_ADDRESS, INA228_CURRENT, (uint8_t *)&iCurrent, 3);
	sign = iCurrent & 0x80;
	iCurrent = __bswap32(iCurrent & 0xFFFFFF) >> 12;
	if (sign) iCurrent += 0xFFF00000;
	fCurrent = (iCurrent) * CURRENT_LSB;                                                     //mA

	return (fCurrent);
}

float ina228_dietemp(uint8_t i2c_master_port)														//获取芯片温度单位？
{
	uint16_t iDieTemp;
	float fDieTemp;

	iDieTemp = i2c_read_short(i2c_master_port, INA228_SLAVE_ADDRESS, INA228_DIETEMP);
	fDieTemp = (iDieTemp) * 0.0078125;

	return (fDieTemp);
}

float ina228_shuntvoltage(uint8_t i2c_master_port)													//获取分流器电压差，单位？
{
	int32_t iShuntVoltage;
	float fShuntVoltage;
	bool sign;

	i2c_read_buf(i2c_master_port, INA228_SLAVE_ADDRESS, INA228_VSHUNT, (uint8_t *)&iShuntVoltage, 3);
	sign = iShuntVoltage & 0x80;
	iShuntVoltage = __bswap32(iShuntVoltage & 0xFFFFFF) >> 12;
	if (sign) iShuntVoltage += 0xFFF00000;

	fShuntVoltage = (iShuntVoltage) * 0.0003125;		// Output in mV when ADCRange = 0
	//fShuntVoltage = (iShuntVoltage) * 0.000078125;	// Output in mV when ADCRange = 1

	return (fShuntVoltage);
}


float ina228_power(uint8_t i2c_master_port)														//获取功率，单位毫瓦？
{
	uint32_t iPower;
	float fPower;

	i2c_read_buf(i2c_master_port, INA228_SLAVE_ADDRESS, INA228_POWER, (uint8_t *)&iPower, 3);
	iPower = __bswap32(iPower & 0xFFFFFF) >> 8;
	fPower = 3.2 * CURRENT_LSB * iPower;

	return (fPower);
}

/*
 * Returns energy in Joules.
 * 1 Watt = 1 Joule per second
 * 1 W/hr = Joules / 3600
 */

float ina228_energy(uint8_t i2c_master_port)													//获取累计电量，单位焦耳J，转瓦时需要/3600？
{
	uint64_t iEnergy;
	float fEnergy;

	i2c_read_buf(i2c_master_port, INA228_SLAVE_ADDRESS, INA228_ENERGY, (uint8_t *)&iEnergy, 5);
	iEnergy = __bswap64(iEnergy & 0xFFFFFFFFFF) >> 24;

	fEnergy = 16 * 3.2 * CURRENT_LSB * iEnergy / 1000;

	return (fEnergy);
}

/*
 * Returns electric charge in Coulombs.
 * 1 Coulomb = 1 Ampere per second.
 * Hence Amp-Hours (Ah) = Coulombs / 3600
 */

float ina228_charge(uint8_t i2c_master_port)													//获取库伦
{
	int64_t iCharge;
	float fCharge;
	bool sign;

	i2c_read_buf(i2c_master_port, INA228_SLAVE_ADDRESS, INA228_CHARGE, (uint8_t *)&iCharge, 5);
	sign = iCharge & 0x80;
	iCharge = __bswap64(iCharge & 0xFFFFFFFFFF) >> 24;
	if (sign) iCharge += 0xFFFFFF0000000000;

	fCharge = CURRENT_LSB * iCharge / 1000;

	return (fCharge);
}

//获取ID
int ina228_get_id(uint8_t i2c_master_port)
{
    uint16_t id = 0;
	id = i2c_read_short(i2c_master_port, INA228_SLAVE_ADDRESS, INA228_DEVICE_ID);
    Printf("id:%04X\n",id);
    
    return id;
}

static inline int cal_volt_raw(int i)
{
    if(!mvar.cal.volt[i].raw){
        return volt_cal_point[i];
    }else{
        return mvar.cal.volt[i].raw;
    }
}

static inline int cal_curt_raw(int i)
{
    if(!mvar.cal.curt[i].raw){
        return curt_cal_point[i];
    }else{
        return mvar.cal.curt[i].raw;
    }
}


float get_cal_volt(float mV)
{
    int a=0,b=0;
    for(int i=0;i<ASIZE(mvar.cal.volt);i++){
        if(mV<cal_volt_raw(i)){
            b=i;
            break;
        }
        a=i;
        b=i;
    }
    if(mvar.cal.volt[a].val==mvar.cal.volt[b].val){
        return mV*mvar.cal.volt[a].val;
    }else{
        if(!mvar.cal.volt[a].raw){
            return mV*mvar.cal.volt[b].val;
        }else if(!mvar.cal.volt[b].raw){
            return mV*mvar.cal.volt[a].val;
        }else{
            float cal=(mvar.cal.volt[b].val-mvar.cal.volt[a].val)*(mV-cal_volt_raw(a))/(cal_volt_raw(b)-cal_volt_raw(a));
            cal=mvar.cal.volt[a].val+cal;
            return mV*cal;
        }
    }
}

float get_cal_curt(float mA)
{
    int a=0,b=0;
    for(int i=0;i<ASIZE(mvar.cal.curt);i++){
        if(mA<cal_curt_raw(i)){
            b=i;
            break;
        }
        a=i;
        b=i;
    }
    if(mvar.cal.curt[a].val==mvar.cal.curt[b].val){
        return mA*mvar.cal.curt[a].val;
    }else{
        if(!mvar.cal.curt[a].raw){
            return mA*mvar.cal.curt[b].val;
        }else if(!mvar.cal.curt[b].raw){
            return mA*mvar.cal.curt[a].val;
        }else{
            float cal=(mvar.cal.curt[b].val-mvar.cal.curt[a].val)*(mA-cal_curt_raw(a))/(cal_curt_raw(b)-cal_curt_raw(a));
            cal=mvar.cal.curt[a].val+cal;
            return mA*cal;
        }
    }
}

void ina228_run(void)
{
	static int mWh_log = 0,mAh_log = 0;			//本次开机后累计值
    float mv=ina228_voltage(0);
    float ma=ina228_current(0);
    float mwh=ina228_energy(0)/3.6;				//单位为焦耳，转mWh需要/3.6
    float mah=ina228_charge(0)/3.6;				//单位为库伦，转mAh需要/3.6
    mvar.msr.mW=ina228_power(0);
    //printf("v_raw:%f  a_raw:%f  mwh:%f  mah:%f  Max_mA:%ld  Max_mW:%ld\n",mv,ma,mwh,mah,mvar.msr.max_mA,mvar.msr.max_mW);
    mvar.msr.raw_mV=mv;
    mvar.msr.raw_mA=ma;
    mvar.msr.mV=get_cal_volt(mv);
    mvar.msr.mA=get_cal_curt(ma);
    mvar.msr.mWH=mwh;
    mvar.msr.mAH=mah;
    mvar.msr.temp=ina228_dietemp(0);

	if (mvar.msr.mWH!=mWh_log) {							//掉电保存毫瓦时
		mWh_log=mvar.msr.mWH;
		mvar.count.Count_mWh=mvar.msr.mWH+mvar.msr.mWh_tmp;
		save_count();
	}

	if (mvar.msr.mAH!=mAh_log) {							//掉电保存毫安时
		mAh_log=mvar.msr.mAH;
		mvar.count.Count_mAh=mvar.msr.mAH+mvar.msr.mAh_tmp;
		save_count();
	}

    if(mvar.msr.mA>mvar.msr.max_mA){						//掉电保存最大正电流
        mvar.msr.max_mA=mvar.msr.mA;
        mvar.count.Count_Max_mA=mvar.msr.max_mA;
        save_count();
    }
    if(mvar.msr.mW>mvar.msr.max_mW){						//掉电保存最大正功率
        mvar.msr.max_mW=mvar.msr.mW;
        mvar.count.Count_Max_mW=mvar.msr.max_mW;
        save_count();
    }
}

void ina228_timer_fun(unsigned long data)
{
    ina228_run();
    mod_timer(&mvar.ina228_timer, jiffies+50);
}


void ina228_task(void *param)
{
    while (1) {
        ina228_run();
        vTaskDelay(50);
    }
}
